﻿using System;
using NUnit.Framework;

namespace Duhking.Tests
{
    [TestFixture]
    public class GenericMethodFinderTests : MethodFinderTestBase
    {
        private GenericMethodFinder _finder;
        public interface GenericMethodTester
        {
            T DoSomething<T>();
            T DoAnotherThing<T, U>(U arg);
            T StillMoreToDo<T>() where T: IDisposable;
        }

        public class GenericMethodTestClass
        {
            public T DoSomething<T>()
            {
                return default(T);
            }

            public T DoAnotherThing<T,U>(U arg)
            {
                return default(T);
            }

            public T StillMoreToDo<T>() where T : IDisposable
            {
                return default(T);
            }
        }

        public class GenericMethodFailureClass
        {
            public T DoNothing<T>()
            {
                return default(T);
            }

            public T DoAnotherThing<T>()
            {
                return default(T);
            }

            public T StillMoreToDo<T>() where T : new()
            {
                return default(T);
            }
        }

        [SetUp]
        public void Setup()
        {
            _finder = new GenericMethodFinder();
        }

        [Test]
        public void FindMatchingMethod_Matches_Method_Name()
        {
            var interfaceMethod = GetMethodInfo("DoSomething",typeof(GenericMethodTester));
            var foundMethod = _finder.FindMatchingMethod(interfaceMethod,typeof(GenericMethodTestClass));
            Assert.That(foundMethod,Is.SameAs(GetMethodInfo("DoSomething",typeof(GenericMethodTestClass))));
        }

        [Test]
        public void FindMathcinMethod_ReturnsNull_If_Matching_Method_Has_Different_Name()
        {
            var interfaceMethod = GetMethodInfo("DoSomething", typeof(GenericMethodTester));
            var foundMethod = _finder.FindMatchingMethod(interfaceMethod, typeof(GenericMethodFailureClass));
            Assert.That(foundMethod, Is.Null);
        }

        [Test]
        public void FindMatchingMethod_Matches_Parameter_Count()
        {
            var interfaceMethod = GetMethodInfo("DoAnotherThing", typeof(GenericMethodTester));
            var foundMethod = _finder.FindMatchingMethod(interfaceMethod, typeof(GenericMethodTestClass));
            Assert.That(foundMethod, Is.SameAs(GetMethodInfo("DoAnotherThing", typeof(GenericMethodTestClass))));
        }

        [Test]
        public void FindMatchingMethod_ReturnsNull_If_Parameter_Counts_Differ()
        {
            var interfaceMethod = GetMethodInfo("DoAnotherThing", typeof(GenericMethodTester));
            var foundMethod = _finder.FindMatchingMethod(interfaceMethod, typeof(GenericMethodFailureClass));
            Assert.That(foundMethod, Is.Null);
        }

        [Test]
        public void FindMatchingMethod_Matches_Parameter_Constraints()
        {
            var interfaceMethod = GetMethodInfo("StillMoreToDo", typeof(GenericMethodTester));
            var foundMethod = _finder.FindMatchingMethod(interfaceMethod, typeof(GenericMethodTestClass));
            Assert.That(foundMethod, Is.SameAs(GetMethodInfo("StillMoreToDo", typeof(GenericMethodTestClass))));
        }

        [Test]
        public void FindMatchingMethod_ReturnsNull_If_Constraints_Dont_Match()
        {
            var interfaceMethod = GetMethodInfo("StillMoreToDo", typeof(GenericMethodTester));
            var foundMethod = _finder.FindMatchingMethod(interfaceMethod, typeof(GenericMethodFailureClass));
            Assert.That(foundMethod, Is.Null);
        }
    }
}
